home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr05 / xnot12a.zip / FILE.C < prev    next >
C/C++ Source or Header  |  1993-06-10  |  25KB  |  1,110 lines

  1. /*
  2.  * File commands. 
  3.  */
  4. #include "jam.h"
  5. #include "stdlib.h"
  6. #include "stdio.h"
  7. #include "def.h"
  8.  
  9. #ifndef WINDOWED
  10. # include "string.h"
  11. #endif
  12.  
  13. #include <time.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16.  
  17. #include "keyname.h"
  18.  
  19. static char rn_(*itos,(char *bufp, unsigned int num));
  20.  
  21. static BOOL touchInsertedLines = FALSE;
  22. static BOOL justwritenewline = FALSE;
  23.  
  24. BOOL clearLineChange = FALSE;
  25. static BOOL revert_hack = FALSE;
  26.  
  27. #ifdef FAT
  28. BOOL no_write_cr = FALSE;  /* to allow MSDOS version to not write CR */
  29. #endif
  30.  
  31. #define VIEW    1
  32. #define REREAD    2
  33. #define REVERT    3
  34.  
  35. static BOOL showFile = TRUE;
  36.  
  37. static char *noWrite = "File is readonly.";
  38. static char *reread = "File changed on disk; reread";
  39. static char *rereadstr = "Reread file: ";
  40. static char *revertostr = "Revert to incremental of: ";
  41. static char *viewstr = "View file: ";
  42. static char *overwritestr = "File changed on disk; overwrite";
  43. static char *noIncFile = "Can not find/open incremental file";
  44. static char *insertanyway = "changed on disk; continue insert";
  45.  
  46. static int rn_(forceinsert,(int f, int n, int flag));
  47. static void rn_(makeIname,(BUFFER *bp));
  48. static int rn_(_poptofile,(int f, int n, BOOL flag));
  49. static BOOL rn_(timechanged,(BUFFER *bp));
  50.  
  51. static BOOL timechanged(bp)
  52. BUFFER *bp;
  53. {
  54.   time_t curtime;
  55.   
  56.   if (bp->b_fname[0])
  57.     getfiletime(bp->b_fname, &curtime);
  58.   
  59.   if (bp->b_fname[0] && bp->b_time && curtime)
  60. #ifdef SUN
  61.     return(bp->b_time == curtime ? TRUE : FALSE);
  62. #else
  63.     return((BOOL)(difftime(bp->b_time, curtime))); /* 0 == no secs different */
  64. #endif
  65.   return(0);
  66. }
  67.  
  68. /* get file time (last mod time) (jam)
  69.  */
  70. void getfiletime(name, p)
  71. char *name;
  72. time_t *p;
  73. {
  74.   struct stat statbuf;
  75.   
  76.   *p = 0; /* invalid time */
  77.   
  78.   if (!stat(name, &statbuf))
  79.     *p = statbuf.st_mtime;
  80. }
  81.  
  82. /* apply cmode as seems fit (JAM)
  83. */
  84. void cmodename(bp, fname)
  85. BUFFER *bp;
  86. char *fname;
  87. {
  88.   BUFFER *save = curbp;
  89.   char copiedname[NFILEN+1];
  90.   char *ptr;
  91.  
  92.   strcpy(copiedname, fname);
  93.   ptr = (char *)strchr(copiedname, '.');
  94.  
  95.   if (ptr++ && *ptr)
  96.    {
  97.      /* known extensions
  98.      */
  99.      if ((strcmp(ptr, "h") == 0) ||
  100.          (strcmp(ptr, "c") == 0) ||
  101.          (strcmp(ptr, "hpp") == 0) ||
  102.          (strcmp(ptr, "cc") == 0) ||
  103.          (strcmp(ptr, "cpp") == 0))
  104.        {
  105.          /* mode not set yet
  106.          */
  107.      if ((bp->b_flag & BFC) == 0)
  108.        {
  109.          curbp = bp;
  110.          blinkparen(0, 1);   /* set the bits... */
  111.          bp->b_flag |= BFC;
  112.          curbp = save;
  113.        }
  114.        }
  115.    }
  116. }
  117.  
  118. /*
  119.  * Insert a file into the current buffer. Real easy - just call the
  120.  * insertfile routine with the file name.
  121.  */
  122. /*ARGSUSED*/
  123. fileinsert(f, n)
  124. int f, n;
  125. {
  126.   register int    s;
  127.   char        fname[NFILEN];
  128.   
  129.   epreload(dirpath());
  130.   if ((s=eread("Insert file: ", fname, NFILEN, EFFILE|EFNEW)) != TRUE)
  131.     return(s);
  132.  
  133.   touchInsertedLines = TRUE;
  134.   s = insertfile(adjustname(fname), (char *) NULL);
  135.   touchInsertedLines = FALSE;
  136.   return (s);
  137.   /* don't set buffer name */
  138. }
  139.  
  140. /*
  141.   
  142.  * Select a file for editing.
  143.  * Look around to see if you can find the
  144.  * fine in another buffer; if you can find it
  145.  * just switch to the buffer. If you cannot find
  146.  * the file, create a new buffer, read in the
  147.  * text, and switch to the new buffer.
  148.  */
  149. /*ARGSUSED*/
  150. filevisit(f, n)
  151. int f, n;
  152. {
  153.   register BUFFER *bp;
  154.   int    s;
  155.   char    fname[NFILEN];
  156.   char    *adjf;
  157.   
  158.   epreload(dirpath());
  159.   if ((s=eread("Find file: ", fname, NFILEN, EFFILE|EFNEW)) != TRUE)
  160.     return(s);
  161.  
  162.   adjf = adjustname(fname);
  163.   if ((bp = findbuffer(adjf)) == NULL) 
  164.     return FALSE;
  165.   
  166. #ifdef DOCRYPT
  167.   setencryptstate((bp->b_flag & BFCRYPT) != 0);
  168. #endif
  169.   if (showbuffer(bp, curwp, WFHARD) != TRUE) 
  170.     return FALSE;
  171.   curbp = bp;
  172.  
  173.   s = FALSE;
  174.   if ((bp->b_fname[0] == 0) || (s = timechanged(bp)))
  175.     {
  176.       int t = TRUE;
  177.       
  178.       if (s)
  179.     t = eyesno(reread);
  180.       if (t)
  181.     {
  182.       t = readin(adjf);        /* Read it in.        */
  183.       if (fileisrdonly(adjf))
  184.         bp->b_flag |= BFVIEW;
  185.       cmodename(bp, adjf);
  186.           getfiletime(bp->b_fname, &bp->b_time); /* reset buf time */
  187.       return(t);
  188.     }
  189.     }
  190.   
  191.   return TRUE;
  192. }
  193. /*
  194.  * Like 'filevisit' above, but rereads (prompt if changes)
  195.  * (JAM)
  196.  */
  197. filerevisit(f, n)
  198. int f, n;
  199. {
  200.   int s = forceinsert(f, n, REREAD);
  201.   return (s);
  202. }
  203. /* Revert to last saved (JAM)
  204.  */
  205. int reverto(f, n)
  206. int f, n;
  207. {
  208.   int s = forceinsert(f, n, REVERT);
  209.   return(s);
  210. }
  211.  
  212. /* Read file, set readonly (JAM)
  213.  */
  214. int fileview(f, n)
  215. int f, n;
  216. {
  217.   int s = forceinsert(f, n, VIEW);
  218.   return(s);
  219. }
  220.  
  221. /* Does work for filerevist, reverto and fileview (JAM)
  222.  * It's ughly but works and I don't want lots of redundant
  223.  * code. Someday filevisit will call this too....
  224.  */
  225. static int forceinsert(f, n, flag)
  226. int f, n, flag;
  227. {
  228.   register BUFFER *bp;
  229.   int    s = TRUE;
  230.   char    fname[NFILEN];
  231.   char    *adjf, *msg;
  232.   char    savename[NFILEN];
  233.   char    saveinc[NFILEN];
  234.   RSIZE line;
  235.  
  236.   if (flag == VIEW)
  237.     epreload(dirpath());
  238.   else
  239.     epreload(curbp->b_fname);
  240.   if (flag == REVERT)
  241.     msg = revertostr;
  242.   else if (flag == VIEW)
  243.     msg = viewstr;
  244.   else 
  245.     msg = rereadstr;
  246.  
  247.   s=eread(msg, fname, NFILEN, EFFILE|EFNEW);
  248.   if (s != TRUE)
  249.     return s;
  250.   adjf = adjustname(fname);
  251.   if ((bp = findbuffer(adjf)) == NULL) 
  252.     return FALSE;
  253.  
  254.   if (flag == REVERT)
  255.     {
  256.       makeIname(bp);
  257.       if (!bp->b_iname || !fileisok(bp->b_iname)) 
  258.     {
  259.       ewprintf(noIncFile);
  260.       bp->b_iname[0] = '\0';
  261.       return FALSE;
  262.     }
  263.     }
  264.  
  265.   if (showbuffer(bp, curwp, WFHARD) != TRUE) 
  266.     return FALSE;
  267.  
  268.   strcpy(savename, bp->b_fname); /* save real file name */
  269.   strcpy(saveinc, bp->b_iname);  /* save restored-from file */
  270.   curbp = bp;
  271.   if ((flag == REVERT) || (flag == REREAD))
  272.     line = getlinenum(curbp, curwp->w_dotp);
  273.   
  274. #ifdef DOCRYPT
  275.   setencryptstate((bp->b_flag & BFCRYPT) != 0);
  276. #endif
  277.   if (flag == REVERT)
  278.     bp->b_flag &= ~BFCHG;      /* don't prompt on revert */
  279.   
  280.   if ((bp->b_fname[0] == 0) || ((bp->b_flag & BFCHG) == 0)
  281.       || ((bp->b_flag = BFCHG) && eyesno("Buffer modified, re-read")))
  282.     {
  283.       bp->b_flag &= ~(BFCHG|BFINC|BFSAVED);         /* don't prompt twice */
  284.       if (flag == REVERT)
  285.     adjf = bp->b_iname;
  286.       if (flag == REREAD)
  287.         revert_hack = TRUE;
  288.       s = readin(adjf);        /* Read it in.    */
  289.       revert_hack = FALSE;
  290.  
  291.       if (s == TRUE)
  292.         {
  293.           if ((flag == VIEW) || fileisrdonly(adjf))
  294.         bp->b_flag |= BFVIEW;
  295.           if ((flag == REVERT) || (flag == REREAD))
  296.         {
  297.           strcpy(bp->b_fname, savename);
  298.           strcpy(bp->b_iname, saveinc);
  299.               getfiletime(bp->b_fname, &bp->b_time); /* reset buf time */
  300.               if (flag == REVERT)
  301.                 bp->b_flag |= (BFCHG | BFINC);     /* needs saving */
  302.               gotobigline(line);
  303.         }
  304.         }
  305.     }
  306.   
  307.   if (s)
  308.     if ((flag != REVERT) && (flag != REREAD))
  309.       cmodename(bp, adjf);
  310.   return (s);
  311. }
  312.  
  313. /*
  314.  * Pop to a file in the other window. Same as last function, just
  315.  * popbuf instead of showbuffer.
  316.  */
  317. /*ARGSUSED*/
  318. poptofile(f, n)
  319. int f, n;
  320. {
  321.   return( _poptofile(f, n, TRUE));
  322. }
  323. /* Other functions call this, not direct user action (JAM)
  324. */
  325. poptofilequiet(f, n)
  326. int f, n;
  327. {
  328.   return( _poptofile(f, n, FALSE));
  329. }
  330. /* Other functions call this, not direct user action (JAM)
  331. */
  332. poptofilehidden(f, n)
  333. int f, n;
  334. {
  335.   int s;
  336.  
  337.   showFile = FALSE;
  338.   s =  _poptofile(f, n, FALSE);
  339.   showFile = TRUE;
  340.   return (s);
  341. }
  342. /* Split from poptofile, and munged (JAM)
  343. */
  344. static int _poptofile(f, n, prompt)
  345. int f,n;
  346. BOOL prompt;
  347. {
  348.   register BUFFER *bp;
  349.   register EWINDOW *wp;
  350.   int    s;
  351.   char    fname[NFILEN];
  352.   char    *adjf;
  353.   
  354.   if (prompt)
  355.       epreload(dirpath());
  356.   if ((s=eread("Find file in other window: ", fname, NFILEN, 
  357.        EFFILE|EFNEW)) != TRUE)
  358.     return(s);
  359.   adjf = adjustname(fname);
  360.   if ((bp = findbuffer(adjf)) == NULL) 
  361.     return FALSE;
  362.  
  363.   if ((wp = popbuf(bp)) == NULL) 
  364.     return FALSE;
  365.   curbp = bp;
  366.   curwp = wp;
  367.  
  368. #ifdef DOCRYPT
  369.   setencryptstate((bp->b_flag & BFCRYPT) != 0);
  370. #endif
  371.  
  372.   s = FALSE;
  373.   if ((bp->b_fname[0] == 0) || (s = timechanged(bp)))
  374.     {
  375.       int t = TRUE;
  376.       
  377.       if (!prompt)
  378.         {
  379.           bp->b_flag &= ~BFCHG; /* no prompt means don't ask about changes */
  380.           t = TRUE;        /* make reread happen */
  381.         }
  382.       else if (s)
  383.     t = eyesno(reread);
  384.  
  385.       if (t)
  386.     {
  387.       t = readin(adjf);        /* Read it in.        */
  388.       if (fileisrdonly(adjf))
  389.         bp->b_flag |= BFVIEW;
  390.       cmodename(bp, adjf);
  391.           getfiletime(adjf, &bp->b_time); /* reset buf time */
  392.       return(t);
  393.     }
  394.     }
  395.   return(TRUE);
  396. }
  397.  
  398. /* Is fname already in a buffer; called
  399. * better have done any file name adjustments for
  400. * case etc because this is an obsolute check.
  401. */
  402. BUFFER *findexistingbuffer(fname)
  403. char *fname;
  404. {
  405.   register BUFFER *bp;
  406.  
  407.   for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) 
  408.     {
  409.       if (fncmp(bp->b_fname, fname) == 0)
  410.         return (bp);
  411.     }
  412.   return(NULL);
  413. }
  414.  
  415. /*
  416.  * Given a file name, either find the buffer it uses, or create a new
  417.  * empty buffer to put it in.
  418.  */
  419. BUFFER *findbuffer(fname)
  420. char *fname;
  421. {
  422.   register BUFFER *bp;
  423.   char    bname[NBUFN], *cp;
  424.   unsigned int count = 1;
  425.  
  426.   bp = findexistingbuffer(fname);
  427.   if (bp)
  428.     return (bp);
  429.   
  430.   makename(bname, fname);            /* New buffer name.    */
  431.   cp = bname + strlen(bname);
  432.   
  433.   /* creating whole name in place vs counting hits
  434.    * first because we don't expect many, if any, name 
  435.    * collisions
  436.    */
  437.   while(bfind(bname, FALSE) != NULL) {
  438.     *cp = '<';        /* add "<count>" to then name    */
  439.     (VOID) strcpy(itos(cp, ++count)+1, ">");
  440.   }
  441.   return bfind(bname, TRUE);
  442. }
  443.  
  444. /*
  445.  * Put the decimal representation of num into a buffer.  Hacked to be
  446.  * faster, smaller, and less general.
  447.  */
  448. static char *itos(bufp, num)
  449. char *bufp;
  450. unsigned int num;
  451. {
  452.   if (num >= 10) {
  453.     bufp = itos(bufp, num/10);
  454.     num %= 10;
  455.   }
  456.   *++bufp = (char)('0' + num);
  457.   return bufp;
  458. }
  459.  
  460. /*
  461.  * Read the file "fname" into the current buffer.
  462.  * Make all of the text in the buffer go away, after checking
  463.  * for unsaved changes. This is called by the "read" command, the
  464.  * "visit" command, and the mainline (for "uemacs file").
  465.  *                                         ^^^^^^ this is old stuff! :)
  466.  */
  467. readin(fname) 
  468. char *fname; 
  469. {
  470.   register int        status;
  471.   register EWINDOW        *wp;
  472.   
  473.   if (bclear(curbp) != TRUE)        /* Might be old.    */
  474.     return TRUE;
  475.   
  476. #ifdef DOCRYPT
  477.   setencryptstate((curbp->b_flag & BFCRYPT) != 0);
  478. #endif
  479.   status = insertfile(fname, fname) ;
  480.   
  481.   /* get the file's last time stamp 
  482.   */
  483.   curbp->b_flag &= ~(BFINC|BFCHG|BFSAVED);
  484.   curbp->b_time = 0;
  485.   getfiletime(fname, &curbp->b_time);
  486.  
  487.   for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
  488.     if (wp->w_bufp == curbp) {
  489.       wp->w_dotp  = wp->w_linep = lforw(curbp->b_linep);
  490.       wp->w_doto  = 0;
  491.       wp->w_markp = NULL;
  492.       wp->w_marko = 0;
  493.     }
  494.   }
  495.  
  496.   /* check for previous crash/death/unexplained 
  497.    * exit (JAM)
  498.    */
  499.   if (!revert_hack)
  500.     {
  501.       makeIname(curbp);
  502.       if (curbp->b_iname && fileisok(curbp->b_iname))
  503.         ewprintf("Incremental save file found; consider revert-to...");
  504.       curbp->b_iname[0] = '\0'; /* tells existance of newly created file */
  505.     }
  506.   return status;
  507. }
  508. /*
  509.  * Insert a file in the current buffer, after dot. Set mark
  510.  * at the end of the text inserted, point at the beginning.
  511.  * Return a standard status. Print a summary (lines read,
  512.  * error message) out as well. If the
  513.  * BACKUP conditional is set, then this routine also does the read
  514.  * end of backup processing. The BFBAK flag, if set in a buffer,
  515.  * says that a backup should be taken. It is set when a file is
  516.  * read in, but not on a new file (you don't need to make a backup
  517.  * copy of nothing).
  518.  */
  519. insertfile(fname, newname) 
  520. char fname[], newname[]; 
  521. {
  522.   register LINE    *lp1;
  523.   register LINE    *lp2;
  524.   register EWINDOW *wp;
  525.   int        nbytes;
  526.   LINE        *olp;            /* Line we started at */
  527.   int        opos;            /* and offset into it */
  528.   int        s, nline;
  529.   BUFFER        *bp;
  530.   char        line[NLINE];
  531.   
  532.   bp = curbp;                /* Cheap.        */
  533.  
  534.   if (timechanged(bp))
  535.     {
  536.       char buff[512];
  537.       
  538.       sprintf(buff, "%s %s", bp->b_fname, insertanyway);
  539.       if (!eyesno(buff))
  540.     goto out;
  541.     }
  542.  
  543. #ifdef WINDOWED  
  544.   WindowSleepCursor();
  545. #endif
  546.   
  547.   if (newname != (char *) NULL)
  548.       (VOID) strcpy(bp->b_fname, newname);
  549.   if ((s=ffropen(fname)) == FIOERR)    /* Hard file open.    */
  550.     goto out;
  551.   if (s == FIOFNF) 
  552.     {            /* File not found.    */
  553.       if (newname != NULL)
  554.     ewprintf("(New file)");
  555.       else    
  556.     ewprintf("(File not found)");
  557.       goto out;
  558.     }
  559.   opos = curwp->w_doto;
  560.  
  561.   /* Open a new line, at point, and start inserting after it 
  562.    */
  563.   (VOID) lnewline();
  564.  
  565.   olp = lback(curwp->w_dotp);
  566.   if (!touchInsertedLines)
  567.     {
  568.       changelineflag(olp, FALSE);
  569.       changelineflag(curwp->w_dotp, FALSE);
  570.     }
  571.  
  572.   if (olp == curbp->b_linep) 
  573.     {
  574.       /* if at end of buffer, create a line to insert before 
  575.        */
  576.       (VOID) lnewline();
  577.       if (!touchInsertedLines)
  578.         changelineflag(curwp->w_dotp, FALSE);
  579.       curwp->w_dotp = lback(curwp->w_dotp);
  580.       if (!touchInsertedLines)
  581.         changelineflag(curwp->w_dotp, FALSE);
  582.     }
  583.  
  584.   nline = 0;            /* Don't count fake line at end */
  585.   while ((s=ffgetline(line, NLINE, &nbytes)) != FIOERR) 
  586.     {
  587.       switch(s) 
  588.     {
  589.     case FIOSUC:
  590.       ++nline;
  591.               /* FALLTHRU and continue */
  592.     case FIOEOF:    /* the last line of the file        */
  593.           if ((lp1=lalloc(nbytes)) == NULL) 
  594.        {
  595.          s = FIOERR;        /* Keep message on the    */
  596.          goto endoffile;        /* display.        */
  597.        }
  598.       if (touchInsertedLines)
  599.             changelineflag(lp1, TRUE);
  600.       bcopy(line, <ext(lp1)[0], (size_t)nbytes);
  601. lineread:
  602.         lp2 = lback(curwp->w_dotp);
  603.       lp2->l_fp = lp1;
  604.       lp1->l_fp = curwp->w_dotp;
  605.       lp1->l_bp = lp2;
  606.       curwp->w_dotp->l_bp = lp1;
  607.       if(s==FIOEOF) 
  608.         goto endoffile;
  609.       break;
  610.     case FIOLONG: 
  611.       {    /* a line to long to fit in our buffer    */
  612.         char *cp;
  613.         char *cp2;
  614.         int     i;
  615.         
  616.         nbytes = 0;
  617.         for(;;) 
  618.           {
  619.         if((cp = malloc((unsigned)(nbytes + NLINE))) == NULL) 
  620.           {
  621.             ewprintf(Nobytes, nbytes + NLINE);
  622.             s = FIOERR;
  623.             if (nbytes && cp2) 
  624.               free(cp2);
  625.             goto endoffile;
  626.           }
  627.         if (nbytes && cp2) 
  628.           {
  629.             bcopy(cp2, cp, (size_t)nbytes);
  630.             free(cp2);
  631.           }
  632.         bcopy(line, cp+nbytes, (size_t)NLINE);
  633.         nbytes += NLINE;
  634.         switch(s = ffgetline(line, NLINE, &i)) 
  635.           {
  636.           case FIOERR:
  637.             free(cp);
  638.             goto endoffile;
  639.           case FIOLONG:
  640.             cp2 = cp;
  641.             break;
  642.           case FIOEOF:
  643.           case FIOSUC:
  644.             if((lp1=lalloc(nbytes+i)) == NULL) 
  645.               {
  646.             s = FIOERR;
  647.             free(cp);
  648.             goto endoffile;
  649.               }
  650.                 if (touchInsertedLines)
  651.                       changelineflag(lp1, TRUE);
  652.             bcopy(cp, <ext(lp1)[0], (size_t)nbytes);
  653.             bcopy(line, <ext(lp1)[nbytes], (size_t)i);
  654.             free(cp);
  655.             goto lineread;
  656.           }
  657.           }
  658.       }
  659.     default:
  660.       ewprintf("Unknown code %d reading file", s);
  661.       s = FIOERR;
  662.       break;
  663.     }
  664.     }
  665.  
  666.  endoffile:
  667.   (VOID) ffclose();            /* Ignore errors.    */
  668.   if (s==FIOEOF) 
  669.     {            /* Don't zap an error.    */
  670.       if (nline == 1) 
  671.     ewprintf("(Read 1 line)");
  672.       else
  673.     ewprintf("(Read %d lines)", nline);
  674.     }
  675.  
  676.   /* Set mark at the end of the text 
  677.    */
  678.   curwp->w_dotp = curwp->w_markp = lback(curwp->w_dotp);
  679.   curwp->w_marko = llength(curwp->w_markp);
  680.   (VOID) ldelnewline();
  681.   if (!touchInsertedLines)
  682.     changelineflag(curwp->w_dotp, FALSE);
  683.   curwp->w_dotp = olp;
  684.   curwp->w_doto = opos;
  685.   if(olp == curbp->b_linep) 
  686.     curwp->w_dotp = lforw(olp);
  687.  
  688.   if (newname != NULL)
  689.     bp->b_flag |= BFCHG | BFBAK | BFINC;    /* Need a backup.    */
  690.   else    
  691.     bp->b_flag |= (BFCHG | BFINC);
  692.     
  693.   /* If the insert was at the end of buffer, set lp1 to the end of
  694.    * buffer line, and lp2 to the beginning of the newly inserted
  695.    * text.  (Otherwise lp2 is set to NULL.)  This is
  696.    * used below to set pointers in other windows correctly if they
  697.    * are also at the end of buffer.
  698.    */
  699.   lp1 = bp->b_linep;
  700.   if (curwp->w_markp == lp1) 
  701.     {
  702.       lp2 = curwp->w_dotp;
  703.     }
  704.   else 
  705.     {
  706.       (VOID) ldelnewline();        /* delete extranious newline */
  707.       if (!touchInsertedLines)
  708.         changelineflag(curwp->w_dotp, FALSE);
  709. out:  
  710.       lp2 = NULL;
  711.     }  
  712.   for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) 
  713.     {
  714.       if (wp->w_bufp == curbp) 
  715.     {
  716.       wp->w_flag |= (WFMODE|WFEDIT);
  717.       if (wp != curwp && lp2 != NULL) 
  718.         {
  719.           if (wp->w_dotp == lp1)    
  720.                 wp->w_dotp  = lp2;
  721.           if (wp->w_markp == lp1) 
  722.                 wp->w_markp = lp2;
  723.           if (wp->w_linep == lp1) 
  724.                 wp->w_linep = lp2;
  725.         }
  726.     }
  727.     }
  728. #ifdef WINDOWED
  729.   WindowNormalCursor();
  730. #endif
  731.   thisflag |= CFNEWF;
  732.   return s != FIOERR;            /* False if error.    */
  733. }
  734.  
  735. /*
  736.  * Take a file name, and from it
  737.  * fabricate a buffer name. This routine knows
  738.  * about the syntax of file names on the target system.
  739.  * BDC1    left scan delimiter.
  740.  *
  741.  * VMS no longer supported cause the code was all wacky (JAM)
  742.  */
  743. VOID makename(bname, fname) 
  744. char bname[]; 
  745. char fname[]; 
  746. {
  747.   register char    *cp1;
  748.   register char    *cp2;
  749.   
  750.   cp1 = &fname[0];
  751.   while (*cp1 != 0)
  752.     ++cp1;
  753.   --cp1;            /* insure at least 1 character ! */
  754.   while (cp1!=&fname[0] && cp1[-1]!=BDC1)
  755.     --cp1;
  756.   cp2 = &bname[0];
  757. #ifdef    BDC3
  758.   while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
  759.     *cp2++ = *cp1++;
  760. #else
  761.   while (cp2!=&bname[NBUFN-1] && *cp1!=0)
  762.     *cp2++ = *cp1++;
  763. #endif
  764.   *cp2 = 0;
  765. }
  766.  
  767. /*
  768.  * Ask for a file name, and write the
  769.  * contents of the current buffer to that file.
  770.  * Update the remembered file name and clear the
  771.  * buffer changed flag. This handling of file names
  772.  * is different from the earlier versions, and
  773.  * is more compatable with Gosling EMACS than
  774.  * with ITS EMACS.
  775.  */
  776. /*ARGSUSED*/
  777. filewrite(f, n)
  778. int f, n;
  779. {
  780.   register int    s;
  781.   char        fname[NFILEN];
  782.   char        *adjfname;
  783.   
  784.   if (curbp->b_fname[0] != '\0')
  785.     epreload(curbp->b_fname);
  786.   else
  787.     epreload(dirpath());
  788.  
  789.   if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
  790.     return (s);
  791.   adjfname = adjustname(fname);
  792.  
  793. #ifdef DOCRYPT
  794.   setencryptstate((curbp->b_flag & BFCRYPT) != 0);
  795. #endif
  796.  
  797.   clearLineChange = TRUE;        /* force linechange flags cleared */
  798.   s=writeout(curbp, adjfname);
  799.   clearLineChange = FALSE;
  800.  
  801.   if (s == TRUE) 
  802.     {
  803.       (VOID) strcpy(curbp->b_fname, adjfname);
  804.       /* zap incremental save file and clear state
  805.        */
  806.       curbp->b_flag &= ~(BFBAK | BFCHG | BFINC);
  807.       if (curbp->b_iname[0]) 
  808.         {
  809.           MakeIncSaveLog();         /* update crash file log */
  810.           unlink(curbp->b_iname);      /* delete it */
  811.           curbp->b_flag &= ~BFSAVED;
  812.         }
  813.       curbp->b_iname[0] = '\0';
  814.  
  815.       /* save this new time stamp
  816.       */
  817.       getfiletime(adjfname, &curbp->b_time);
  818.       if (showtouchedlines)
  819.         upmodes(WFHARD);    /* because LFCHANGE */
  820.     }
  821.  
  822.   return s;
  823. }
  824.  
  825. /*
  826.  * Save the contents of the current buffer back into
  827.  * its associated file.
  828.  */
  829. #define    MAKEBACKUP TRUE
  830. static int    makebackup = MAKEBACKUP;
  831.  
  832. /*ARGSUSED*/
  833. int filesave(f, n)
  834. int f, n;
  835. {
  836.   return buffsave(curbp);
  837. }
  838. /*
  839.  * Save the contents of the buffer argument into its associated file.
  840.  * Do nothing if there have been no changes
  841.  * (is this a bug, or a feature). Error if there is no remembered
  842.  * file name. If this is the first write since the read or visit,
  843.  * then a backup copy of the file is made.
  844.  * Allow user to select whether or not to make backup files
  845.  * by looking at the value of makebackup.
  846.  */
  847. buffsave(bp) 
  848. BUFFER *bp; 
  849. {
  850.   register int    s;
  851.  
  852.   /* Somebody else touch the file? Check first...
  853.   */  
  854.   if (timechanged(bp))
  855.     if (eyesno(overwritestr) != TRUE)
  856.       return(FALSE);
  857.  
  858.   if ((bp->b_flag & BFCHG) == 0)    {    /* Return, no changes.    */
  859.     ewprintf("(No changes need to be saved)");
  860.     return TRUE;
  861.   }
  862.  
  863.   if (bp->b_fname[0] == '\0') {        /* Must have a name.    */
  864.     ewprintf("No file name");
  865.     return (FALSE);
  866.   }
  867.   
  868.   if (makebackup && (bp->b_flag&BFBAK)) 
  869.     {
  870.       s = fbackupfile(bp->b_fname);
  871.       if (s == ABORT)            /* Hard error.        */
  872.     return FALSE;
  873.       if (s == FALSE            /* Softer error.    */
  874.       && (s=eyesno("Backup error, save anyway")) != TRUE)
  875.     return s;
  876.     }
  877.  
  878. #ifdef DOCRYPT
  879.   setencryptstate((bp->b_flag & BFCRYPT) != 0);
  880. #endif
  881.  
  882.   clearLineChange = TRUE;        /* force linechange flags cleared */
  883.   s = writeout(bp, bp->b_fname);
  884.   clearLineChange = FALSE;
  885.  
  886.   if (s == TRUE) 
  887.     {
  888.       /* update mod time if writting named buffer
  889.        */
  890.       getfiletime(bp->b_fname, &bp->b_time);
  891.     
  892.       /* zap incremental save file and clear state
  893.        */
  894.       bp->b_flag &= ~(BFINC | BFCHG | BFBAK);
  895.       if (bp->b_iname[0])
  896.         {
  897.           unlink(bp->b_iname);      /* delete it */
  898.           curbp->b_flag &= ~BFSAVED;
  899.           MakeIncSaveLog();         /* update crash file log */
  900.         }
  901.       bp->b_iname[0] = '\0';
  902.       if (showtouchedlines)
  903.         upmodes(WFHARD);  /* because LFCHANGED */
  904.     }
  905.   return s;
  906. }
  907.  
  908. /* Since we don't have variables (we probably should)
  909.  * this is a command processor for changing the value of
  910.  * the make backup flag.  If no argument is given,
  911.  * sets makebackup to true, so backups are made.  If
  912.  * an argument is given, no backup files are made when
  913.  * saving a new version of a file. Only used when BACKUP
  914.  * is #defined.
  915.  */
  916. /*ARGSUSED*/
  917. makebkfile(f, n)
  918. int f, n;
  919. {
  920.   if(f & FFARG) 
  921.     makebackup = n > 0;
  922.   else 
  923.     makebackup = !makebackup;
  924.   ewprintf("Backup files %sabled", makebackup ? "en" : "dis");
  925.   return TRUE;
  926. }
  927.  
  928. /*
  929.  * This function performs the details of file
  930.  * writing; writing the file in buffer bp to
  931.  * file fn. Uses the file management routines
  932.  * in the "fileio.c" package. Most of the grief
  933.  * is checking of some sort.
  934.  */
  935. writeout(bp, fn) 
  936. register BUFFER *bp; 
  937. char *fn; 
  938. {
  939.   register int    s;
  940.   
  941. #ifdef DOCRYPT
  942.   setencryptstate((bp->b_flag & BFCRYPT) != 0);
  943. #endif
  944.   if ((s=ffwopen(fn)) != FIOSUC)        /* Open writes message. */
  945.     return (FALSE);
  946.  
  947. #ifdef WINDOWED
  948.   WindowSleepCursor();
  949. #endif
  950.  
  951. #ifdef FAT
  952.   if (bp->b_flag & BFC)       /* hack to let C source files not have CR */
  953.     if (justwritenewline)
  954.       no_write_cr = TRUE;
  955. #endif
  956.  
  957.   s = ffputbuf(bp);
  958.   
  959. #ifdef FAT
  960.   no_write_cr = FALSE;
  961. #endif
  962.  
  963.   if (s == FIOSUC) {            /* No write error.    */
  964.     s = ffclose();
  965.     if (s==FIOSUC)
  966.       ewprintf("Wrote %s", fn);
  967.   } else                /* Ignore close error    */
  968.     (VOID) ffclose();            /* if a write error.    */
  969. #ifdef WINDOWED
  970.   WindowNormalCursor();
  971. #endif
  972.   return s == FIOSUC;
  973. }
  974.  
  975. /*
  976.  * Tag all windows for bp (all windows if bp NULL) as needing their
  977.  * mode line updated.
  978.  */
  979. VOID upmodes(f) 
  980. int f;            /* additional modes, WFMODE always set  */ 
  981. {
  982.   register EWINDOW *wp;
  983.   int flags = WFMODE;
  984.  
  985.   if (f)
  986.     flags |= f;
  987.   for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
  988.     wp->w_flag |= flags;
  989. }
  990.  
  991. /* Incremental save function - called from
  992.  * timer interrupt code...(JAM)
  993.  */
  994. void IncrementalSave()
  995. {
  996.   register BUFFER *bp;
  997.   int wasVis = IsCaretVis();
  998.   BOOL msg = FALSE;
  999.   
  1000.   SetCaretVis(FALSE);
  1001.   
  1002.   for (bp = bheadp; bp != NULL; bp = bp->b_bufp) 
  1003.     if (bp->b_fname[0] && ((bp->b_flag & BFINC) != 0))
  1004.       {
  1005.     if (!msg)
  1006.       ewprintf(garbage);
  1007.     msg = TRUE;
  1008.     
  1009.     /* construct name 
  1010.      */ 
  1011.     if (!bp->b_iname[0])
  1012.       makeIname(bp);
  1013.     
  1014.     /* make sure name is ok
  1015.      */
  1016.     if (!bp->b_iname[0])
  1017.           continue;           /* internal error */
  1018.     
  1019.     /* save the file
  1020.      */
  1021.     if (writeout(bp, bp->b_iname) != TRUE) 
  1022.       ewprintf("Unable to write %s", bp->b_iname);
  1023.         else
  1024.           bp->b_flag |= BFSAVED;
  1025.     bp->b_flag &= ~BFINC;   /* too bad! */
  1026.       }
  1027.   
  1028.   if (msg)
  1029.     {
  1030.       MakeIncSaveLog();        /* need to update if changes saved */
  1031.       upmodes(0);        /* need to force modeline redraw */
  1032.       update();
  1033.     }
  1034.   
  1035.   /* reset cursor pos... turn it back on
  1036.    */
  1037.   if (wasVis)
  1038.     SetCaretVis(TRUE);
  1039. }
  1040.  
  1041. /* Make incremental name (JAM)
  1042.  */
  1043. static void makeIname(bp)
  1044. BUFFER *bp;
  1045. {
  1046. #ifdef FAT
  1047. # define EXTLEN 5
  1048.   char ext[EXTLEN];
  1049.   register char *ptr;
  1050.  
  1051.   strcpy(bp->b_iname, bp->b_fname);
  1052.   ptr = (char *)strchr(bp->b_iname, '.');
  1053.   memset(ext, '%', EXTLEN);
  1054.   ext[0] = '.';
  1055.   ext[3] = (ptr && *(ptr+1) ? *(ptr+1) : '#');
  1056.   ext[4] = '\0';
  1057.   
  1058.   if (ptr)
  1059.     strcpy(ptr, ext);
  1060.   else
  1061.     strcat(bp->b_iname, ext);   
  1062.  
  1063. #else /* unix */
  1064.   strcpy(bp->b_iname, bp->b_fname);
  1065.   strcat(bp->b_iname, "+");
  1066. #endif
  1067.   
  1068.   if (!bp->b_iname[0] || (strcmp(bp->b_fname, bp->b_iname) == 0))
  1069.     bp->b_iname[0] = '\0';  /* failed, zap name */ 
  1070. }
  1071.  
  1072.  
  1073. static verifytime = FALSE;
  1074. int toggleverifytime(f, n)
  1075. int f, n;
  1076. {
  1077.   verifytime = verifytime ? FALSE : TRUE;
  1078.   ewprintf("Timestamp checking is %s during editting.", 
  1079.             verifytime ? "enabled" : "disabled");
  1080.   return (TRUE);
  1081. }
  1082.  
  1083. BOOL filetimechanged(bp)
  1084. BUFFER *bp;
  1085. {
  1086.   BOOL flag = FALSE; 
  1087.  
  1088.   if (verifytime)        /* enabled? */
  1089.     if (flag = timechanged(bp))
  1090.       {
  1091.         ttbeep();
  1092.         if (eyesno("File changed on disk! Edit this file") == TRUE)
  1093.           {
  1094.             getfiletime(bp->b_fname, &bp->b_time);    /* reset buf time */
  1095.             ewprintf("Timestamp synced.");
  1096.             flag = FALSE;                /* date synced */
  1097.           }
  1098.       }
  1099.   return (flag);
  1100. }
  1101.  
  1102. int togglejustnl(f,n)
  1103. int f, n;
  1104. {
  1105.   justwritenewline = justwritenewline ? FALSE : TRUE;
  1106.   ewprintf("Newline only on write (not CR) for C/H files is %s.", 
  1107.             justwritenewline ? "enabled" : "disabled");
  1108.   return (TRUE);
  1109. }
  1110.